package cn.juque.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.juque.common.abstracts.AbstractRequestDTO;
import cn.juque.common.base.BaseRequestVO;
import cn.juque.common.base.BaseResponseDTO;
import cn.juque.common.base.PageInfo;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.exception.AppException;
import lombok.Data;
import org.hibernate.validator.HibernateValidator;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author nuoka
 * @version 1.0.0
 * <li>IntelliJ IDEA</li>
 * <li>cn.juque.consumer.utils</li>
 * @date 2020/1/29 13:14
 **/
public class ValidatorUtil {

    public ValidationResult validate(Object object, Class<?>... groups) {
        Validator validator = this.initValidator();
        ValidationResult validationResult = new ValidationResult();
        if (null == object) {
            return validationResult;
        }

        Set<ConstraintViolation<Object>> constraintViolationSet = validator.validate(object, groups);
        if (constraintViolationSet.isEmpty()) {
            return validationResult;
        }

        constraintViolationSet.forEach(constraintViolation -> {
            validationResult.setHasError(Boolean.TRUE);
            String msg = constraintViolation.getMessage();
            String propertyName = constraintViolation.getPropertyPath().toString();
            validationResult.getErrMsgMap().put(propertyName, msg);
        });
        return validationResult;
    }

    /**
     * 校验请求参数对象，如果出现未校验通过的，直接抛出异常
     *
     * @param object 待处理的对象
     * @param groups 校验分组
     */
    public void fastValidate(Object object, Class<?>... groups) {
        if (null == object) {
            throw new AppException(MessageEnum.PARAM_NULL);
        }
        ValidationResult validationResult = this.validate(object, groups);
        if (null == validationResult || !validationResult.getHasError()) {
            return;
        }

        //请求参数存在不合法的数据，这里直接抛出异常
        Map<String, String> map = validationResult.getErrMsgMap();
        String errorMsg = MessageEnum.BAD_REQUEST.getMsg();
        if (map.isEmpty()) {
            throw new AppException(MessageEnum.BAD_REQUEST.getCode(), errorMsg);
        }
        errorMsg = map.entrySet().iterator().next().getValue();
        throw new AppException(MessageEnum.BAD_REQUEST.getCode(), errorMsg);
    }

    /**
     * 校验请求参数对象，如果出现未校验通过的，直接抛出异常
     *
     * @param collection 待处理的对象列表
     * @param groups 校验分组
     */
    public void fastValidate(Collection<?> collection, Class<?>... groups) {
        if (CollUtil.isEmpty(collection)) {
            throw new AppException(MessageEnum.PARAM_NULL);
        }
        collection.parallelStream().forEach(t-> this.fastValidate(t, groups));
    }

    /**
     * 参数校验
     *
     * @param requestDto BaseRequestDTO
     * @param groups     校验组
     */
    public void fastValidate(AbstractRequestDTO requestDto, Class<?>... groups) {
        if (null == requestDto) {
            throw new AppException(MessageEnum.PARAM_NULL);
        }
        this.fastValidate((Object) requestDto, groups);
    }

    /**
     * 参数校验
     *
     * @param requestVo BaseRequestDTO
     * @param groups    校验组
     */
    public void fastValidate(BaseRequestVO<?> requestVo, Class<?>... groups) {
        if (null == requestVo) {
            throw new AppException(MessageEnum.PARAM_NULL);
        }
        this.fastValidate(requestVo.getParam(), groups);
    }

    /**
     * 入参为空则抛出异常
     *
     * @param req http报文
     * @param <T> parna
     * @return T
     */
    public <T> T checkNotNull(BaseRequestVO<T> req) {
        if (null == req || ObjectUtil.isEmpty(req.getParam())) {
            throw new AppException(MessageEnum.PARAM_NULL);
        }
        return req.getParam();
    }

    /**
     * 入参为空则抛出异常
     *
     * @param req http报文
     */
    public void checkNotNull(AbstractRequestDTO req) {
        if (null == req) {
            throw new AppException(MessageEnum.PARAM_NULL);
        }
    }

    /**
     * 检查分页信息是否存在
     * @param pageInfo 分页信息
     */
    public void checkPageInfo(PageInfo pageInfo) {
        boolean b = null != pageInfo && null != pageInfo.getPage() && null != pageInfo.getLimit();
        if (!b) {
            throw new AppException(MessageEnum.PAGE_NULL);
        }
    }

    /**
     * 如果dubbo请求成功，则返回报文应对象
     *
     * @param resp dubbo报文
     * @param <T>  对象
     * @return T
     */
    public <T> T successful(BaseResponseDTO<T> resp) {
        if (null == resp) {
            throw new AppException(MessageEnum.SYSTEM_ERROR);
        }
        if (!MessageEnum.OK.getCode().equals(resp.getCode())) {
            throw new AppException(resp.getCode(), resp.getMsg());
        }

        return resp.getData();
    }

    /**
     * 初始化验证器
     */
    private Validator initValidator() {
        try(ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure().failFast(Boolean.TRUE)
                .buildValidatorFactory()) {
            return validatorFactory.getValidator();
        }
    }

    /**
     * @author nuoka 内置结果处理类
     */
    @Data
    private static class ValidationResult {

        /**
         * 是否存在错误
         */
        private Boolean hasError = Boolean.FALSE;

        /**
         * 错误的信息的map
         */
        private Map<String, String> errMsgMap = new HashMap<>();
    }
}
